﻿using Nes.Core.Buss;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace Nes.Core
{
    public interface ICPU
    {
        CPURegister Register { get; }
        IBus Bus { get; }
        void Clock();
        void Reset();
        void IRQ();
        void NMI();
    }

    public class CPURegister
    {
        public const Int32 SPBaseAddr = 0x100; 
        /// <summary>
        /// 程序计数器，记录下一条指令地址
        /// 范围
        /// </summary>
        public UInt16 PC { get; set; }
        /// <summary>
        /// 堆栈寄存器，值为 0x00 ~ 0xFF，对应 CPU 总线上的 0x100 ~ 0x1FF
        /// </summary>
        public Byte SP { get; set; }
        /// <summary>
        /// 实际只用 6bit
        /// <see cref="P_Flag"/>
        /// </summary>
        public Byte P { get; set; } 
        /// <summary>
        /// 累加器
        /// </summary>
        public Byte A { get; set; } 
        /// <summary>
        /// 循环计数
        /// </summary>
        public Byte X { get; set; }
        /// <summary>
        /// 循环计数
        /// </summary>
        public Byte Y { get; set; }

        public void Reset(UInt16 pc)
        {
            PC = pc; SP = 0xfd; P = 0; A = 0; X = 0; Y = 0;
            //SetPFlag(P_Flag.U, true);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public Boolean JudgePFlag(Byte flag)
        {
            return (P & flag) ==  flag;
        }

        /// <summary>
        /// 计算结果是否为0
        /// </summary>
        /// <param name="data"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetZFlag(Int32 data)
        {
            this.SetPFlag(P_Flag.Z, (data & 0xff) == 0);
        }

        /// <summary>
        /// 计算结果是否为负
        /// </summary>
        /// <param name="data"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetNFlag(Int32 data)
        {
            this.SetPFlag(P_Flag.N, (data & 0x80) > 0);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetPFlag(Byte flag, Boolean value)
        {
            if (value)
            {
                P |= flag;
            }
            else
            {
                P &= (Byte)(~flag);
            }
        }
    }

    public static class P_Flag
    {
        /// <summary>
        /// 进位标志，如果计算结果产生进位，则置 1
        /// </summary>
        public const Byte C = 1 << 0;
        /// <summary>
        /// 零标志，如果计算结果为 0，则置 1
        /// </summary>
        public const Byte Z = 1 << 1;
        /// <summary>
        /// 中断去使能标志，置 1 则可屏蔽掉 IRQ 中断
        /// </summary>
        public const Byte I = 1 << 2;
        /// <summary>
        /// 十进制模式，未使用
        /// </summary>
        public const Byte D = 1 << 3;
        /// <summary>
        /// BRK
        /// </summary>
        public const Byte B = 1 << 4;
        /// <summary>
        /// 未使用 常为1
        /// </summary>
        public const Byte U = 1 << 5;
        /// <summary>
        /// 溢出标志，如果结算结果产生了溢出，则置 1
        /// </summary>
        public const Byte V = 1 << 6;
        /// <summary>
        /// 负标志，如果计算结果为负，则置 1
        /// </summary>
        public const Byte N = 1 << 7;
    }

    public class CPU : ICPU
    {
        #region InterruptVector
        private const UInt16 Interrupt_NMI = 0xFFFA;
        private const UInt16 Interrupt_Reset = 0xFFFC;
        private const UInt16 Interrupt_IRQ = 0xFFFE;
        #endregion

        private Byte[][] OpCodes = null;

        private Int32 Clocks = 0;
        private Int32 Num = 0;
        private Int32 CyclesToHalt = 0;
        private Int32 Cycles = 0;
        private Int32 SuspendCycles = 0;

        public CPURegister Register { get; private set; }
        public IBus Bus { get; private set; }

        public CPU(IBus cpuBus)
        {
            Bus = cpuBus;
            Register = new CPURegister();
            OpCodes = OpCode.GetOpCodes();
        }

        public void Clock()
        {
            if (SuspendCycles > 0) 
            {
                SuspendCycles--;
                return;
            }
            if (CyclesToHalt == 0)
            {
                Num++;
                this.Emulate();
            }
            this.CyclesToHalt--;
            Clocks++;
        }

        private void Emulate()
        {
#if debug
            var _pc = Register.PC;
#endif
            // 读取指令
            var opcode = this.Bus.ReadByte(this.Register.PC++);
            /// 0-7 inst
            /// 8-15 addr
            /// 16-23 size
            /// 24-31 sysles
            //var opInfo = BitConverter.GetBytes(OpCodes[opcode]);
            var opInfo = OpCodes[opcode];
            // 指令
            var inst = opInfo[0];
            // 读取取地址模式
            var addrModel = opInfo[1];
            // 获取数据大小
            var dataSize = opInfo[2];
            // 时钟数
            var cycles = opInfo[3];


            var readData = (addrModel) switch
            {
                OpCode.ADDR_ZP => ZeroPage(),
                OpCode.ADDR_REL => Relative(),
                OpCode.ADDR_IMP => Implicit(),
                OpCode.ADDR_ABS => Absolute(),
                OpCode.ADDR_ACC => Accumulator(),
                OpCode.ADDR_IMM => Immediate(),
                OpCode.ADDR_ZPX => ZeroPageX(),
                OpCode.ADDR_ZPY => ZeroPageY(),
                OpCode.ADDR_ABSX => AbsoluteX(),
                OpCode.ADDR_ABSY => AbsoluteY(),
                OpCode.ADDR_IDX => IndirectX(),
                OpCode.ADDR_IDY => IndirectY(),
                OpCode.ADDR_INDABS => Indirect(),
            };


           
            // 额外的时钟
            var cycleAdd = readData.CrossPage ? 1 : 0;
#if debug
            var regStr = $"A:{Register.A:X2} X:{Register.X:X2} Y:{Register.Y:X2} P:{Register.P:X2} SP:{Register.SP:X2}";
#endif
            // 执行指令
            switch (inst)
            {
                case OpCode.INS_ADC: InsADC(readData, addrModel); break; //
                case OpCode.INS_AND: InsAND(readData, addrModel); break; // ？
                case OpCode.INS_ASL: InsASL(readData, addrModel); break; //

                case OpCode.INS_BCC: InsBCC(readData, addrModel); break; //
                case OpCode.INS_BCS: InsBCS(readData, addrModel); break; //
                case OpCode.INS_BEQ: InsBEQ(readData, addrModel); break; //
                case OpCode.INS_BIT: InsBIT(readData, addrModel); break; //
                case OpCode.INS_BMI: InsBMI(readData, addrModel); break; //
                case OpCode.INS_BNE: InsBNE(readData, addrModel); break; //
                case OpCode.INS_BPL: InsBPL(readData, addrModel); break; //
                case OpCode.INS_BRK: InsBRK(readData, addrModel); break;
                case OpCode.INS_BVC: InsBVC(readData, addrModel); break; //
                case OpCode.INS_BVS: InsBVS(readData, addrModel); break; //

                case OpCode.INS_CLC: InsCLC(readData, addrModel); break; //
                case OpCode.INS_CLD: InsCLD(readData, addrModel); break; //
                case OpCode.INS_CLI: InsCLI(readData, addrModel); break;
                case OpCode.INS_CLV: InsCLV(readData, addrModel); break; //
                case OpCode.INS_CMP: InsCMP(readData, addrModel); break; //
                case OpCode.INS_CPX: InsCPX(readData, addrModel); break; //
                case OpCode.INS_CPY: InsCPY(readData, addrModel); break; //

                case OpCode.INS_DEC: InsDEC(readData, addrModel); break;
                case OpCode.INS_DEX: InsDEX(readData, addrModel); break; //
                case OpCode.INS_DEY: InsDEY(readData, addrModel); break; //
                case OpCode.INS_EOR: InsEOR(readData, addrModel); break; //

                case OpCode.INS_INC: InsINC(readData, addrModel); break;
                case OpCode.INS_INX: InsINX(readData, addrModel); break; //
                case OpCode.INS_INY: InsINY(readData, addrModel); break; //

                case OpCode.INS_JMP: InsJmp(readData, addrModel); break; //
                case OpCode.INS_JSR: InsJSR(readData, addrModel); break; //

                case OpCode.INS_LDA: InsLDA(readData, addrModel); break; //
                case OpCode.INS_LDX: InsLDX(readData, addrModel); break; //
                case OpCode.INS_LDY: InsLDY(readData, addrModel); break; //
                case OpCode.INS_LSR: InsLSR(readData, addrModel); break; //
                case OpCode.INS_NOP: break;                              //

                case OpCode.INS_ORA: InsORA(readData, addrModel); break; //
                case OpCode.INS_PHA: InsPHA(readData, addrModel); break; //
                case OpCode.INS_PHP: InsPHP(readData, addrModel); break; //
                case OpCode.INS_PLA: InsPLA(readData, addrModel); break; //
                case OpCode.INS_PLP: InsPLP(readData, addrModel); break; //

                case OpCode.INS_ROL: InsROL(readData, addrModel); break;
                case OpCode.INS_ROR: InsROR(readData, addrModel); break;
                case OpCode.INS_RTI: InsRTI(readData, addrModel); break;
                case OpCode.INS_RTS: InsRTS(readData, addrModel); break; //

                case OpCode.INS_SBC: InsSBC(readData, addrModel); break; //
                case OpCode.INS_SEC: InsSEC(readData, addrModel); break; //
                case OpCode.INS_SED: InsSED(readData, addrModel); break; //
                case OpCode.INS_SEI: InsSEI(readData, addrModel); break; //
                case OpCode.INS_STA: InsSTA(readData, addrModel); break; //
                case OpCode.INS_STX: InsSTX(readData, addrModel); break; //
                case OpCode.INS_STY: InsSTY(readData, addrModel); break;

                case OpCode.INS_TAX: InsTAX(readData, addrModel); break; //
                case OpCode.INS_TAY: InsTAY(readData, addrModel); break; //
                case OpCode.INS_TSX: InsTSX(readData, addrModel); break; //
                case OpCode.INS_TXA: InsTXA(readData, addrModel); break; //
                case OpCode.INS_TXS: InsTXS(readData, addrModel); break; //
                case OpCode.INS_TYA: InsTYA(readData, addrModel); break; //

                case OpCode.INS_ALR: InsALR(readData, addrModel); break;
                case OpCode.INS_ANC: InsANC(readData, addrModel); break;
                case OpCode.INS_ARR: InsARR(readData, addrModel); break;
                case OpCode.INS_AXS: InsAXS(readData, addrModel); break;

                case OpCode.INS_LAX: InsLAX(readData, addrModel); break;
                case OpCode.INS_SAX: InsSAX(readData, addrModel); break;
                case OpCode.INS_DCP: InsDCP(readData, addrModel); break;
                case OpCode.INS_ISC: InsISC(readData, addrModel); break;
                case OpCode.INS_RLA: InsRLA(readData, addrModel); break;
                case OpCode.INS_RRA: InsRRA(readData, addrModel); break;
                case OpCode.INS_SLO: InsSLO(readData, addrModel); break;
                case OpCode.INS_SRE: InsSRE(readData, addrModel); break;
                case OpCode.INS_SKB: InsSKB(readData, addrModel); break;
                case OpCode.INS_IGN: InsIGN(readData, addrModel); break;

                default:
                    throw new NotImplementedException();
            };
            CyclesToHalt += (cycles + cycleAdd);
#if debug
            var log = $"{Num:0000} -> {_pc:X} {opcode:X} {OpCode.InstName[inst]} {readData.ToLog()} \t\t\t {regStr}";
            Console.WriteLine(log);
            if (Num < 1081)
            {
                Console.WriteLine();
            }
            else
            {
                Console.ReadLine();
            }
#endif
        }


        /// <summary>
        /// 可屏蔽中断
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        public void IRQ()
        {
            if (Register.JudgePFlag(P_Flag.I))
            {
                return;
            }
            PushWord(Register.PC);
            Push((Byte)((Register.P | P_Flag.U) & ~P_Flag.B));
            Register.SetPFlag(P_Flag.I, true);
            Register.PC = Bus.ReadWord(Interrupt_IRQ);
            CyclesToHalt += 7;
        }

        /// <summary>
        /// 不可屏蔽中断
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        public void NMI()
        {
            PushWord(Register.PC);
            Push((Byte)((Register.P | P_Flag.U) & ~P_Flag.B));
            Register.SetPFlag(P_Flag.I, true);
            Register.PC = Bus.ReadWord(Interrupt_NMI);
            CyclesToHalt += 7;
        }

        /// <summary>
        /// 复位
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        public void Reset()
        {
            Register.Reset(Bus.ReadWord(Interrupt_Reset));
            CyclesToHalt = 8;
            Clocks = 0;
        }

        #region Stack Opera
        private void PushWord(UInt16 data)
        {
            Push((Byte)(data >> 8));
            Push((Byte)data);

        }
        private void Push(Byte data)
        {
            Bus.WriteByte(CPURegister.SPBaseAddr + Register.SP, data);
            Register.SP--;
        }
        private UInt16 PopWord()
        {
            return (UInt16)(Pop() | Pop() << 8);
        }
        private Byte Pop()
        {
            Register.SP++;
            return Bus.ReadByte(CPURegister.SPBaseAddr + Register.SP);
        }
        #endregion


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static Boolean PageCrossed(Int32 addr1, Int32 addr2)
        {
            return (addr1 & 0xff00) != (addr2 & 0xff00);
        }

        //[MethodImpl(MethodImplOptions.AggressiveInlining)]
        //private void HaltCycles(Int32 cycles)
        //{
        //    this.CyclesToHalt += cycles;
        //}

        #region Instructions

        /// <summary>
        /// A:=A+{adr}
        /// <para></para>
        /// N	V	B	D	I	Z	C
        /// *	*	 	 	 	*	*
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsADC(ReadAddressResult readData, Byte addrModel)
        {
            var data = GetData(readData);
            var value = data + this.Register.A + (this.Register.JudgePFlag(P_Flag.C) ? 1 : 0);
            Register.SetPFlag(P_Flag.C, value > 0xff);
            Register.SetNFlag(value);
            Register.SetZFlag(value);
            if (((Register.A ^ data) & 0x80) == 0 && ((Register.A ^ value) & 0x80) != 0)
            {
                Register.SetPFlag(P_Flag.V, true);
            }
            else
            {
                Register.SetPFlag(P_Flag.V, false);
            }
            this.Register.A = (Byte)value;

        }

        /// <summary>
        /// A:=A&{adr}
        /// <para></para>
        /// N	V	B	D	I	Z	C
        /// *	 	 	 	 	*	 
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsAND(ReadAddressResult readData, Byte addrModel)
        {
            var data = GetData(readData);
            var value = data & this.Register.A;
            Register.SetZFlag(value);
            Register.SetNFlag(value);
            Register.A = (Byte)value;
        }

        /// <summary>
        /// branch on V=1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsBVS(ReadAddressResult readData, byte addrModel)
        {
            if (Register.JudgePFlag(P_Flag.V))
            {
                CyclesToHalt++;
                if(PageCrossed(Register.PC, readData.Address.Value))
                {
                    CyclesToHalt++;
                }
                Register.PC = readData.Address.Value;
            }
        }

        /// <summary>
        /// branch on V=0
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsBVC(ReadAddressResult readData, byte addrModel)
        {
            if (!Register.JudgePFlag(P_Flag.V))
            {
                CyclesToHalt++;
                if (PageCrossed(Register.PC, readData.Address.Value))
                {
                    CyclesToHalt++;
                }
                Register.PC = readData.Address.Value;
            }
        }

        /// <summary>
        /// (S)-:=PC,P PC:=($FFFE)
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsBRK(ReadAddressResult readData, byte addrModel)
        {
            PushWord(Register.PC);
            Push((Byte)(Register.P | P_Flag.B | P_Flag.U));
            Register.SetPFlag(P_Flag.I, true);
            Register.PC = this.Bus.ReadWord(Interrupt_IRQ);
        }

        /// <summary>
        /// branch on N=0
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsBPL(ReadAddressResult readData, byte addrModel)
        {
            if (!Register.JudgePFlag(P_Flag.N))
            {
                CyclesToHalt++;
                if (PageCrossed(Register.PC, readData.Address.Value))
                {
                    CyclesToHalt++;
                }
                Register.PC = readData.Address.Value;
            }
        }

        /// <summary>
        /// branch on Z=0
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsBNE(ReadAddressResult readData, byte addrModel)
        {
            if (!Register.JudgePFlag(P_Flag.Z))
            {
                CyclesToHalt++;
                if (PageCrossed(Register.PC, readData.Address.Value))
                {
                    CyclesToHalt++;
                }
                Register.PC = readData.Address.Value;
            }
        }

        /// <summary>
        /// branch on N=1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsBMI(ReadAddressResult readData, byte addrModel)
        {
            if (Register.JudgePFlag(P_Flag.N))
            {
                CyclesToHalt++;
                if (PageCrossed(Register.PC, readData.Address.Value))
                {
                    CyclesToHalt++;
                }
                Register.PC = readData.Address.Value;
            }
        }

        /// <summary>
        /// N:=b7 V:=b6 Z:=A&{adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsBIT(ReadAddressResult readData, byte addrModel)
        {
            var data = GetData(readData);
            Register.SetPFlag(P_Flag.Z, (Register.A & data) == 0);
            Register.SetPFlag(P_Flag.N, (data & P_Flag.N) > 0);
            Register.SetPFlag(P_Flag.V, (data & P_Flag.V) > 0);
        }

        /// <summary>
        /// branch on Z=1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsBEQ(ReadAddressResult readData, byte addrModel)
        {
            if (Register.JudgePFlag(P_Flag.Z))
            {
                CyclesToHalt++;
                if (PageCrossed(Register.PC, readData.Address.Value))
                {
                    CyclesToHalt++;
                }
                Register.PC = readData.Address.Value;
            }
        }

        /// <summary>
        /// branch on C=1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsBCS(ReadAddressResult readData, byte addrModel)
        {
            if (Register.JudgePFlag(P_Flag.C))
            {
                CyclesToHalt++;
                if (PageCrossed(Register.PC, readData.Address.Value))
                {
                    CyclesToHalt++;
                }
                Register.PC = readData.Address.Value;
            }
        }

        /// <summary>
        /// branch on C=0
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsBCC(ReadAddressResult readData, byte addrModel)
        {
            if (!Register.JudgePFlag(P_Flag.C))
            {
                CyclesToHalt++;
                if (PageCrossed(Register.PC, readData.Address.Value))
                {
                    CyclesToHalt++;
                }
                Register.PC = readData.Address.Value;
            }
        }

        /// <summary>
        /// {adr}:={adr}*2
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsASL(ReadAddressResult readData, byte addrModel)
        {
            var data = GetData(readData) << 1;
            Register.SetPFlag(P_Flag.C, (data & 0x100) > 0);
            Register.SetNFlag(data);
            Register.SetZFlag(data);

            if (readData.Address.HasValue)
            {
                Bus.WriteByte(readData.Address.Value, (Byte)data);
            }
            else
            {
                Register.A = (Byte)data;
            }
        }

        /// <summary>
        /// Y-{adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsCPY(ReadAddressResult readData, byte addrModel)
        {
            var data = GetData(readData);
            var result = Register.Y - data;
            Register.SetPFlag(P_Flag.C, Register.Y >= data);
            Register.SetNFlag(result);
            Register.SetZFlag(result);
        }

        /// <summary>
        /// X-{adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsCPX(ReadAddressResult readData, byte addrModel)
        {
            var data = GetData(readData);
            var result = Register.X - data;
            Register.SetPFlag(P_Flag.C, Register.X >= data);
            Register.SetNFlag(result);
            Register.SetZFlag(result);
        }

        /// <summary>
        /// A-{adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsCMP(ReadAddressResult readData, byte addrModel)
        {
            var data = GetData(readData);
            var result = Register.A - data;
            Register.SetPFlag(P_Flag.C, Register.A >= data);
            Register.SetNFlag(result);
            Register.SetZFlag(result);
        }

        /// <summary>
        /// Y:=Y-1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsDEY(ReadAddressResult readData, byte addrModel)
        {
            var data = Register.Y - 1;
            Register.SetNFlag(data);
            Register.SetZFlag(data);
            Register.Y = (Byte)data;
        }

        /// <summary>
        /// X:=X-1 
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsDEX(ReadAddressResult readData, byte addrModel)
        {
            var data = Register.X - 1;
            Register.SetNFlag(data);
            Register.SetZFlag(data);
            Register.X = (Byte)data;
        }

        /// <summary>
        /// {adr}:={adr}-1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsDEC(ReadAddressResult readData, byte addrModel)
        {
            var data = GetData(readData);
            var val = data - 1;
            Register.SetNFlag(val);
            Register.SetZFlag(val);
            Bus.WriteByte(readData.Address.Value, (Byte)val);
        }

        /// <summary>
        /// A:=A exor {adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsEOR(ReadAddressResult readData, byte addrModel)
        {
            Register.A ^= GetData(readData);
            Register.SetNFlag(Register.A);
            Register.SetZFlag(Register.A);
        }

        /// <summary>
        /// Y:=Y+1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsINY(ReadAddressResult readData, byte addrModel)
        {
            Register.Y++;
            Register.SetNFlag(Register.Y);
            Register.SetZFlag(Register.Y);
        }

        /// <summary>
        /// X:=X+1 
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsINX(ReadAddressResult readData, byte addrModel)
        {
            Register.X++;
            Register.SetNFlag(Register.X);
            Register.SetZFlag(Register.X);
        }

        /// <summary>
        /// {adr}:={adr}+1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsINC(ReadAddressResult readData, byte addrModel)
        {
            var data = GetData(readData);
            var val = (Byte)(data + 1);
            Register.SetNFlag(val);
            Register.SetZFlag(val);
            Bus.WriteByte(readData.Address.Value, val);
        }

        /// <summary>
        /// PC:={adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsJmp(ReadAddressResult readData, Byte addrModel)
        {
            Register.PC = readData.Address.Value;
        }

        /// <summary>
        /// (S)-:=PC PC:={adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsJSR(ReadAddressResult readData, Byte addrModel)
        {
            PushWord((UInt16)(Register.PC - 1));
            Register.PC = readData.Address.Value;
        }

        /// <summary>
        /// X:={adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsLDX(ReadAddressResult readData, Byte addrModel)
        {
            Register.X = GetData(readData);
            Register.SetNFlag(Register.X);
            Register.SetZFlag(Register.X);
        }

        /// <summary>
        /// Y:={adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsLDY(ReadAddressResult readData, Byte addrModel)
        {
            Register.Y = GetData(readData);
            Register.SetNFlag(Register.Y);
            Register.SetZFlag(Register.Y);
        }

        /// <summary>
        /// A:={adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsLDA(ReadAddressResult readData, Byte addrModel)
        {
            Register.A = GetData(readData);
            Register.SetNFlag(Register.A);
            Register.SetZFlag(Register.A);
        }

        /// <summary>
        /// {adr}:={adr}/2
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsLSR(ReadAddressResult readData, Byte addrModel)
        {
            var data = GetData(readData);
            Register.SetPFlag(P_Flag.C, (data & 0x01) > 0);
            data >>= 1;
            Register.SetNFlag(data);
            Register.SetZFlag(data);
            if (readData.Address.HasValue)
            {
                Bus.WriteByte(readData.Address.Value, data);
            }
            else
            {
                Register.A = data;
            }
        }

        /// <summary>
        /// C:=0
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsCLC(ReadAddressResult readData, Byte addrModel)
        {
            Register.SetPFlag(P_Flag.C, false);
        }

        /// <summary>
        /// C:=1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSEC(ReadAddressResult readData, Byte addrModel)
        {
            Register.SetPFlag(P_Flag.C, true);
        }

        /// <summary>
        /// D:=0
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsCLD(ReadAddressResult readData, Byte addrModel)
        {
            Register.SetPFlag(P_Flag.D, false);
        }

        /// <summary>
        /// D:=1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSED(ReadAddressResult readData, Byte addrModel)
        {
            Register.SetPFlag(P_Flag.D, true);
        }

        /// <summary>
        /// V:=0
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsCLV(ReadAddressResult readData, Byte addrModel)
        {
            Register.SetPFlag(P_Flag.V, false);
        }

        /// <summary>
        /// I:=0
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsCLI(ReadAddressResult readData, Byte addrModel)
        {
            Register.SetPFlag(P_Flag.I, false);
        }

        /// <summary>
        /// I:=1
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSEI(ReadAddressResult readData, Byte addrModel)
        {
            Register.SetPFlag(P_Flag.I, true);
        }

        /// <summary>
        /// {adr}:=A
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSTA(ReadAddressResult readData, Byte addrModel)
        {
            this.Bus.WriteByte(readData.Address.Value, Register.A);
        }

        /// <summary>
        /// {adr}:=X
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSTX(ReadAddressResult readData, Byte addrModel)
        {
            this.Bus.WriteByte(readData.Address.Value, Register.X);
        }
        /// <summary>
        /// {adr}:=Y
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSTY(ReadAddressResult readData, Byte addrModel)
        {
            this.Bus.WriteByte(readData.Address.Value, Register.Y);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsIGN(ReadAddressResult readData, byte addrModel)
        {
            GetData(readData);

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSKB(ReadAddressResult readData, byte addrModel)
        {
            return;
        }

        /// <summary>
        /// {adr}:={adr}/2 A:=A exor {adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSRE(ReadAddressResult readData, byte addrModel)
        {
            InsLSR(readData, addrModel);
            InsEOR(readData, addrModel);
        }

        /// <summary>
        /// {adr}:={adr}*2 A:=A or {adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSLO(ReadAddressResult readData, byte addrModel)
        {
            InsASL(readData, addrModel);
            InsORA(readData, addrModel);
        }

        /// <summary>
        /// {adr}:={adr}ror A:=A adc {adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsRRA(ReadAddressResult readData, byte addrModel)
        {
            InsROR(readData, addrModel);
            InsADC(readData, addrModel);
        }

        /// <summary>
        /// {adr}:={adr}rol A:=A and {adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsRLA(ReadAddressResult readData, byte addrModel)
        {
            InsROL(readData, addrModel);
            InsAND(readData, addrModel);
        }

        /// <summary>
        /// {adr}:={adr}+1 A:=A-{adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsISC(ReadAddressResult readData, byte addrModel)
        {
            InsINC(readData, addrModel);
            InsSBC(readData, addrModel);
        }

        /// <summary>
        /// {adr}:={adr}-1 A-{adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsDCP(ReadAddressResult readData, byte addrModel)
        {
            InsDEC(readData, addrModel);
            InsCMP(readData, addrModel);
        }

        /// <summary>
        /// {adr}:=A&X
        /// 
        /// SAX {adr} = store A&X into {adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSAX(ReadAddressResult readData, byte addrModel)
        {
            var data = (Byte)(Register.A & Register.X);
            Bus.WriteByte(readData.Address.Value, data);
        }

        /// <summary>
        /// A,X:={adr}
        /// 
        /// LAX {adr} = LDA {adr} + LDX {adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsLAX(ReadAddressResult readData, byte addrModel)
        {
            InsLDA(readData, addrModel);
            InsLDX(readData, addrModel);
        }

        /// <summary>
        /// X:=A&X-#{imm}
        /// 
        /// AXS #{imm} = A&X minus #{imm} into X
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsAXS(ReadAddressResult readData, byte addrModel)
        {
            var tmp = GetData(readData);
            var data = (Byte)((Register.X & Register.A) - GetData(readData));
            Register.SetNFlag(Register.X);
            Register.SetZFlag(Register.X);
            Register.SetPFlag(P_Flag.C, (Register.X & 0x80) > 0);
            var v = (((Register.X ^ data) & 0x80) != 0) && (((Register.X ^ tmp) & 0x80) != 0);
            Register.SetPFlag(P_Flag.V, v);
            Register.X = data;
        }

        /// <summary>
        /// A:=(A&#{imm})/2
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsARR(ReadAddressResult readData, byte addrModel)
        {
            var tmp = Register.A & GetData(readData);
            tmp = tmp >> 1 + (Register.JudgePFlag(P_Flag.C) ? 1 : 0);
            // N V Z C
            Register.SetNFlag(tmp);
            Register.SetZFlag(tmp);
            Register.SetPFlag(P_Flag.V, ((tmp >> 7) ^ (tmp >> 6)) > 0);
            Register.SetPFlag(P_Flag.C, (tmp >> 7) > 0);
        }

        /// <summary>
        /// A:=A&#{imm}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsANC(ReadAddressResult readData, byte addrModel)
        {
            var tmp = Register.A & GetData(readData);
            // N Z C
            Register.SetNFlag(tmp);
            Register.SetZFlag(tmp);
            Register.SetPFlag(P_Flag.C, (tmp >> 7) > 0);
            Register.A = (Byte)tmp;
        }

        /// <summary>
        /// A:=(A&#{imm})/2
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsALR(ReadAddressResult readData, byte addrModel)
        {
            var tmp = (Register.A & GetData(readData)) >> 1;
            // N Z C
            Register.SetNFlag(tmp);
            Register.SetZFlag(tmp);
            Register.SetPFlag(P_Flag.C, (tmp >> 7) > 0);
            Register.A = (Byte)tmp;
        }

        /// <summary>
        /// S:=X
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsTXS(ReadAddressResult readData, byte addrModel)
        {
            Register.SP = Register.X;
        }

        /// <summary>
        /// A:=Y
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsTYA(ReadAddressResult readData, byte addrModel)
        {
            Register.A = Register.Y;
            Register.SetNFlag(Register.A);
            Register.SetZFlag(Register.A);
        }

        /// <summary>
        /// A:=X
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsTXA(ReadAddressResult readData, byte addrModel)
        {
            Register.A = Register.X;
            Register.SetNFlag(Register.A);
            Register.SetZFlag(Register.A);
        }

        /// <summary>
        /// X:=S
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsTSX(ReadAddressResult readData, byte addrModel)
        {
            Register.X = Register.SP;
            Register.SetNFlag(Register.X);
            Register.SetZFlag(Register.X);
        }

        /// <summary>
        /// Y:=A
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsTAY(ReadAddressResult readData, byte addrModel)
        {
            Register.Y = Register.A;
            Register.SetNFlag(Register.Y);
            Register.SetZFlag(Register.Y);
        }

        /// <summary>
        /// X:=A
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsTAX(ReadAddressResult readData, byte addrModel)
        {
            Register.X = Register.A;
            Register.SetNFlag(Register.X);
            Register.SetZFlag(Register.X);
        }

        /// <summary>
        /// A:=A-#{imm}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsSBC(ReadAddressResult readData, byte addrModel)
        {
            var data = GetData(readData);
            var result = Register.A - data - (Register.JudgePFlag(P_Flag.C) ? 0 : 1);
            Register.SetZFlag(result);
            Register.SetNFlag(result);
            var v = (((Register.A ^ result) & 0x80) != 0) && (((Register.A ^ data) & 0x80) != 0); 
            Register.SetPFlag(P_Flag.V ,v);
            Register.SetPFlag(P_Flag.C , result >= 0);
            Register.A = (Byte)(result & 0xff);
        }

        /// <summary>
        /// PC:=+(S)
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsRTS(ReadAddressResult readData, byte addrModel)
        {
            //Register.PC = (UInt16)(PopWord());
            Register.PC = (UInt16)(PopWord() + 1);
        }

        /// <summary>
        /// P,PC:=+(S)
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsRTI(ReadAddressResult readData, byte addrModel)
        {
            Register.P = Pop();
            Register.SetPFlag(P_Flag.B, false);
            Register.SetPFlag(P_Flag.U, true);
            Register.PC = PopWord();
        }

        /// <summary>
        /// {adr}:={adr}/2+C*128
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsROR(ReadAddressResult readData, byte addrModel)
        {
            Int32 data = GetData(readData);
            var tmpAdd = (Register.JudgePFlag(P_Flag.C) ? 0x80 : 0);
            Register.SetPFlag(P_Flag.C, (data & 0x01) > 0);
            data = (data >> 1) +  tmpAdd;
            Register.SetNFlag(data);
            Register.SetZFlag(data);
            if (readData.Address.HasValue)
            {
                Bus.WriteByte(readData.Address.Value, (Byte)data);
            }
            else
            {
                Register.A = (Byte)data;
            }
        }

        /// <summary>
        /// {adr}:={adr}*2+C
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsROL(ReadAddressResult readData, byte addrModel)
        {
            Int32 data = GetData(readData);
            var tmpAdd = (Register.JudgePFlag(P_Flag.C) ? 1 : 0);
            Register.SetPFlag(P_Flag.C, (data & 0x80) > 0);
            data = (data << 1) + tmpAdd;
            Register.SetNFlag(data);
            Register.SetZFlag(data);
            if (readData.Address.HasValue)
            {
                Bus.WriteByte(readData.Address.Value, (Byte)data);
            }
            else
            {
                Register.A = (Byte)data;
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsPLP(ReadAddressResult readData, byte addrModel)
        {
            Register.P = Pop();
            Register.SetPFlag(P_Flag.B, false);
            Register.SetPFlag(P_Flag.U, true);
        }

        /// <summary>
        /// A:=+(S)
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsPLA(ReadAddressResult readData, byte addrModel)
        {
            Register.A = Pop();
            Register.SetNFlag(Register.A);
            Register.SetZFlag(Register.A);
        }

        /// <summary>
        /// (S)-:=P
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsPHP(ReadAddressResult readData, byte addrModel)
        {
            Push((Byte)(Register.P | P_Flag.B | P_Flag.U));
        }

        /// <summary>
        /// (S)-:=A
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsPHA(ReadAddressResult readData, byte addrModel)
        {
            Push(Register.A);
        }

        /// <summary>
        /// A:=A or {adr}
        /// </summary>
        /// <param name="readData"></param>
        /// <param name="addrModel"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void InsORA(ReadAddressResult readData, byte addrModel)
        {
            Register.A |= GetData(readData);
            Register.SetNFlag(Register.A);
            Register.SetZFlag(Register.A);
        }
        #endregion

        #region 寻址
        /// <summary>
        /// 特殊寻址 数据长度0
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult Implicit() 
        {
            return new ReadAddressResult();
        }
        /// <summary>
        /// 累加器寻址 数据长度0
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult Accumulator() 
        {
            return new ReadAddressResult()
            {
                Data = this.Register.A,
            };
        }

        /// <summary>
        /// 立即寻址 数据长度0
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult Immediate() 
        {
            return new ReadAddressResult(){
                Data = this.Bus.ReadByte(this.Register.PC++),
            };
        }
        /// <summary>
        /// 数据长度1
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult ZeroPage() 
        {
            return new ReadAddressResult()
            {
                Address = Bus.ReadByte(this.Register.PC++)
            };
        }

        /// <summary>
        /// 数据长度1
        /// </summary>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult ZeroPageX()
        {
            return new ReadAddressResult()
            {
                Address = (UInt16)((this.Bus.ReadByte(this.Register.PC++) + this.Register.X) & 0xff)
            };
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult ZeroPageY() 
        {
            return new ReadAddressResult()
            {
                Address = (UInt16)((this.Bus.ReadByte(this.Register.PC++) + this.Register.Y) & 0xff)
            };
        }

        /// <summary>
        /// 间接寻址（只有 JMP 使用）
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult Indirect()
        {
            var address = this.Bus.ReadWord(this.Register.PC);
            this.Register.PC++;
            this.Register.PC++;
            if((address & 0xff) == 0xff)
            {
                address = (UInt16)((Bus.ReadByte(address & 0xFF00) << 8) | Bus.ReadByte(address));
            }
            else
            {
                address = this.Bus.ReadWord(address);

            }
            return new ReadAddressResult()
            {
                Address = address
            };
        }
        /// <summary>
        /// 返回值为（(X + ?)的地址中的值的地址的值）
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult IndirectX()
        {
            var address = this.Bus.ReadByte(this.Register.PC++) + this.Register.X;
            var l = this.Bus.ReadByte(address & 0xff);
            var h = this.Bus.ReadByte((address + 1) & 0xff);
            return new ReadAddressResult { Address = (UInt16)(h << 8 | l) };
        }
        /// <summary>
        /// 地址的值为 （？ + Y
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult IndirectY()
        {
            var address = this.Bus.ReadByte(this.Register.PC++);
            var l = this.Bus.ReadByte(address & 0xff);
            var h = this.Bus.ReadByte((address + 1) & 0xff);
            var address2 = (UInt16)(h << 8 | l);
            var address3 = (UInt16)(address2 + Register.Y);
            return new ReadAddressResult { Address = address3, CrossPage = JudgeCrossPage(address2, address3) };
        }

        /// <summary>
        /// 绝对寻址
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult Absolute()
        {
            var address = this.Bus.ReadWord(this.Register.PC); 
            this.Register.PC++;
            this.Register.PC++;
            return new ReadAddressResult() { Address = address };
        }
        /// <summary>
        /// 绝对寻址 + X
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult AbsoluteX()
        {
            var address = this.Bus.ReadWord(this.Register.PC);
            this.Register.PC++;
            this.Register.PC++;
            var address2 = (UInt16)(address + this.Register.X);
            return new ReadAddressResult() { Address = address2, CrossPage = JudgeCrossPage(address, address2) };
        }
        /// <summary>
        /// 绝对寻址 + Y
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult AbsoluteY()
        {
            var address = this.Bus.ReadWord(this.Register.PC);
            this.Register.PC++;
            this.Register.PC++;
            var address2 = (UInt16)(address + this.Register.Y);
            return new ReadAddressResult() { Address = address2, CrossPage = JudgeCrossPage(address, address2)};
        }

        /// <summary>
        /// 相对寻址
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private ReadAddressResult Relative()
        {
            Int32 offset = this.Bus.ReadByte(this.Register.PC++);
            if(offset > 128)
            {
                offset = offset - 256;
            }
            return new ReadAddressResult() { Address = (UInt16)(offset + this.Register.PC) };
        }


        #endregion


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static Boolean JudgeCrossPage(UInt16 addr1, UInt16 addr2)
        {
            return (addr1 & 0xff00) != (addr2 & 0xff00);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private Byte GetData(ReadAddressResult readData)
        {
            return readData.Data ?? Bus.ReadByte(readData.Address.Value);
        }

        internal void SetSuspendCycles()
        {
            this.SuspendCycles = (Cycles & 0x01) > 0 ? 513 : 514; 
        }
    }

    /// <summary>
    /// 寻址结果
    /// </summary>
    public class ReadAddressResult
    {
        /// <summary>
        /// 指向的地址
        /// </summary>
        public UInt16? Address { get; set; }
        /// <summary>
        /// 指向的数据
        /// </summary>
        public Byte? Data { get; set; }
        /// <summary>
        /// 是否跨页
        /// </summary>
        public Boolean CrossPage { get; set; }

        internal String ToLog()
        {
            return Address.HasValue ? $"${Address.Value:X4}" : Data.HasValue? $"#{Data.Value:X2}\t" : "\t";
        }
    }
}
